package pfq.demo.threads

import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.view.View
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import pfq.demo.R
import java.util.concurrent.Callable
import java.util.concurrent.Executors
import java.util.concurrent.Future

/**
 * 在Java线程池相关的API中，有以下类或接口需要熟悉：
 * 1. Executor，接口，其中只定义了一个execute()方法
 * 2. ExecutorService，接口，继承于Executor，定义了更丰富的操作线程池的方法，比如submit()表示提交一个Runnable或者Callable开始执行；shutdown()方法表示停止线程池所有的线程，但如果正在执行会等到执行完再结束线程池；shutdownNow()表示会立即停止所有线程，即使有正在执行的线程。
 * 3. AbstractExecutorService，抽象类，实现了ExecutorService接口
 * 4. ThreadPoolExecutor，类，继承于AbstractExecutorService类，用于自定义一个线程池对象，通过构造函数传入很多参数来进行创建
 * 5. Executors，类，定义了很多静态类用于创建线程池，相当于创建线程池的工厂类，当然内部也是通过new一个ThreadPoolExecutor对象来实现的
 *
 * 在Android中，有：
 * 1. AsyncTask
 * 2. HandlerThread
 */
class ThreadPoolActivity : AppCompatActivity(), View.OnClickListener {

    private var tv1: TextView? = null
    private var pb1: ProgressBar? = null
    private var startBtn1: Button? = null
    private var stopBtn1: Button? = null

    private var tv2: TextView? = null
    private var pb2: ProgressBar? = null
    private var startBtn2: Button? = null
    private var stopBtn2: Button? = null

    // 此处注意，如果使用的是Executors.newSingleThreadPool()创建的线程池只会有一个线程，所以开启线程1后，线程2需要等线程1执行完毕才可以开始执行
    private val executorService = Executors.newCachedThreadPool()

    private var handler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)

            when (msg.what) {
                ARGS_THREAD_1 -> {
                    tv1?.text = "线程1：" + msg.arg1
                    pb1?.progress = msg.arg1
                }
                ARGS_THREAD_2 -> {
                    tv2?.text = "线程2：" + msg.arg1
                    pb2?.progress = msg.arg1
                }
            }

        }
    }

    private var callable1: Callable<Int>? = null
    private var future1: Future<Int>? = null

    private var callable2: Callable<Int>? = null
    private var future2: Future<Int>? = null

    companion object {
        const val ARGS_THREAD_1 = 0x000
        const val ARGS_THREAD_2 = 0x001
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_thread_pool)

        tv1 = findViewById(R.id.activity_thread_pool_tv1)
        pb1 = findViewById(R.id.activity_thread_pool_pb1)
        startBtn1 = findViewById(R.id.activity_thread_pool_start_btn1)
        stopBtn1 = findViewById(R.id.activity_thread_pool_stop_btn1)

        tv2 = findViewById(R.id.activity_thread_pool_tv2)
        pb2 = findViewById(R.id.activity_thread_pool_pb2)
        startBtn2 = findViewById(R.id.activity_thread_pool_start_btn2)
        stopBtn2 = findViewById(R.id.activity_thread_pool_stop_btn2)

        startBtn1?.setOnClickListener(this)
        stopBtn1?.setOnClickListener(this)

        startBtn2?.setOnClickListener(this)
        stopBtn2?.setOnClickListener(this)

        pb1?.progress = 0
        pb1?.max = 100

        pb2?.progress = 0
        pb2?.max = 100

    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.activity_thread_pool_start_btn1 -> {

                var num = 0

                callable1 = Callable {
                    while (num < 100) {

                        num++

                        sendMsg(ARGS_THREAD_1, num)

                        Thread.sleep(100)
                    }

                    520
                }

                future1 = executorService.submit(callable1)
            }
            R.id.activity_thread_pool_stop_btn1 -> {
                if (!executorService.isShutdown) {
                    future1?.cancel(true)
                }
            }

            R.id.activity_thread_pool_start_btn2 -> {

                var num = 0;
                callable2 = Callable {
                    while (num < 100) {

                        num++

                        sendMsg(ARGS_THREAD_2, num)

                        Thread.sleep(100)
                    }

                    520
                }

                future2 = executorService.submit(callable2)
            }
            R.id.activity_thread_pool_stop_btn2 -> {
                if (!executorService.isShutdown) {
                    future2?.cancel(true)
                }
            }
        }
    }

    private fun sendMsg(what: Int, arg: Int) {
        val msg = Message.obtain()
        msg.what = what
        msg.arg1 = arg
        handler.sendMessage(msg)
    }
}
